package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.AssertUtils;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author wangyuqing
 * @since 2024-08-20
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {
    private final CourseClient courseClient;
    private final CatalogueClient catalogueClient;


    /**
     * 1.添加课程到我的课表
     *
     * @param userId
     * @param courseIds
     * @return
     */
    @Override
    @Transactional
    public void addUserLessons(Long userId, List<Long> courseIds) {
        //1.根据课程iDs查询课程信息
        List<CourseSimpleInfoDTO> courseList = courseClient.getSimpleInfoList(courseIds);
        //2.判断课程是否为空，为空直接返回，
        if (ObjectUtil.isEmpty(courseList)) {
            log.error("课程信息为空，无法添加课程");
            return;
        }
        //3.循环遍历，处理LearningLesson数据，
        List<LearningLesson> lessons = new ArrayList<>();
        for (CourseSimpleInfoDTO course : courseList) {
            LearningLesson Lesson = new LearningLesson();
            //获取课程的有效期
            Integer validDuration = course.getValidDuration();
            if (ObjectUtil.isNotEmpty(validDuration) && validDuration > 0) {
                //设置课表的过期时间
                Lesson.setExpireTime(LocalDateTime.now().plusMonths(validDuration));
                //填充userId和courseId
                Lesson.setCourseId(course.getId());
                Lesson.setUserId(userId);
                lessons.add(Lesson);
            }
        }
        //批量插入
        saveBatch(lessons);
    }

    /**
     * 2.分页查询我的课表
     *
     * @param pageQuery
     * @return
     */
    @Override
    public PageDTO<LearningLessonVO> queryMyLessons(PageQuery pageQuery) {
        //1.获取用户ID
        Long userId = UserContext.getUser();
        //2.分页查询课程
//        //2.1构建分页对象
//        Page<LearningLesson> page = new Page<>(pageQuery.getPageNo(), pageQuery.getPageSize());
//        //2.2指定分页排序的条件
//        if (ObjectUtil.isNotEmpty(pageQuery.getSortBy())) {
//            page.addOrder(new OrderItem(pageQuery.getSortBy(), pageQuery.getIsAsc()));
//        } else {
//            page.addOrder(OrderItem.desc("latest_learn_time"));
//        }
        Page<LearningLesson> page = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .page(pageQuery.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = page.getRecords();
        if (ObjectUtil.isEmpty(records)) {
            return PageDTO.empty(page);
        }

        //3.发起远程调用，查询到课程信息
        //3.1收集当前页码的所有课程ID集合
        Set<Long> courseIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());
        //3.2发起远程调用，查询课程详细信息
        List<CourseSimpleInfoDTO> courseInfoList = courseClient.getSimpleInfoList(courseIds);
        //3.3健壮性判断
        if (ObjectUtil.isEmpty(courseInfoList)) {
            throw new BizIllegalException("课程信息为空");
        }
        //将分页集合封装成LearningLessonVO集合，
        List<LearningLessonVO> vos = new ArrayList<>();
        Map<Long, CourseSimpleInfoDTO> courseInfoMap = courseInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, Function.identity()));
        for (LearningLesson lesson : records) {
            //4.1将lesson转成LearningLessonVO
            LearningLessonVO vo = BeanUtil.toBean(lesson, LearningLessonVO.class);
            //4.2获取课程的特有信息（课程名称，封面，总课时数）
            CourseSimpleInfoDTO courseInfo = courseInfoMap.get(lesson.getCourseId());
            vo.setCourseName(courseInfo.getName());
            vo.setCourseCoverUrl(courseInfo.getCoverUrl());
            vo.setSections(courseInfo.getSectionNum());
            //4.3存入vo集合
            vos.add(vo);
        }
        //5.封装PageDTO，返回
        return PageDTO.of(page, vos);
    }


    /**
     * 3、查询我正在学习的课程（Day2 - 作业1）
     *
     * @return
     */
    @Override
    public LearningLessonVO queryMyCurrentLesson() {
        // 1.获取当前登录的用户
        Long userId = UserContext.getUser();
        // 2.查询正在学习的课程 select * from xx where user_id = #{userId} AND status = 1 order by latest_learn_time limit 1
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1")
                .one();
        if (lesson == null) {
            return null;
        }
        // 3.拷贝PO基础属性到VO
        LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);
        // 4.查询课程信息
        CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
        if (cInfo == null) {
            throw new BadRequestException("课程不存在");
        }
        vo.setCourseName(cInfo.getName());
        vo.setCourseCoverUrl(cInfo.getCoverUrl());
        vo.setSections(cInfo.getSectionNum());
        // 5.统计课表中的课程数量 select count(1) from xxx where user_id = #{userId}
        Integer courseAmount = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .count();
        vo.setCourseAmount(courseAmount);
        // 6.查询小节信息
        List<CataSimpleInfoDTO> cataInfos =
                catalogueClient.batchQueryCatalogue(CollUtils.singletonList(lesson.getLatestSectionId()));
        if (!CollUtils.isEmpty(cataInfos)) {
            CataSimpleInfoDTO cataInfo = cataInfos.get(0);
            vo.setLatestSectionName(cataInfo.getName());
            vo.setLatestSectionIndex(cataInfo.getCIndex());
        }
        return vo;
    }


    /**
     * 4、查询指定课程信息（Day2 - 作业2）
     *
     * @param courseId
     * @return
     */
    @Override
    public LearningLessonVO queryLessonByCourseId(Long courseId) {
        // 1.获取当前登录用户
        Long userId = UserContext.getUser();
        // 2.查询课程信息 select * from xx where user_id = #{userId} AND course_id = #{courseId}
        LearningLesson lesson = getOne(buildUserIdAndCourseIdWrapper(userId, courseId));
        if (lesson == null) {
            return null;
        }
        // 3.处理VO
        return BeanUtils.copyBean(lesson, LearningLessonVO.class);
    }


    /**
     * 5、删除指定课程信息（Day2 - 作业3）
     *
     * @param userId
     * @param courseId
     */
    @Override
    public void deleteCourseFromLesson(Long userId, Long courseId) {
        if (userId == null) {
            userId = UserContext.getUser();
        }
        // 2.删除课程
        remove(buildUserIdAndCourseIdWrapper(userId, courseId));
    }


    /**
     * 6、统计课程学习人数（Day2 - 作业4）
     *
     * @param courseId
     * @return
     */
    @Override
    public Integer countLearningLessonByCourse(Long courseId) {
        // select count(1) from xx where course_id = #{cc} AND status in (0, 1, 2)
        return lambdaQuery()
                .eq(LearningLesson::getCourseId, courseId)
                .in(LearningLesson::getStatus,
                        LessonStatus.NOT_BEGIN.getValue(),
                        LessonStatus.LEARNING.getValue(),
                        LessonStatus.FINISHED.getValue())
                .count();
    }


    /**
     * 创建学习计划
     *
     * @param courseId 课程ID
     * @param freq     每周学习频率
     * @return
     */
    @Override
    public void createLearningPlan(Long courseId, Integer freq) {
        // 1、查询课表信息
        LearningLesson lesson = getOne(buildUserIdAndCourseIdWrapper(UserContext.getUser(), courseId));
        AssertUtils.isNotNull(lesson, "课表信息不存在");

        // 2、更新学习计划数据
        this.lambdaUpdate()
                .set(LearningLesson::getWeekFreq,freq)
                .set(lesson.getPlanStatus() == PlanStatus.NO_PLAN, LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .eq(LearningLesson::getId, lesson.getId())
                .update();
    }

    /**
     * 查询课表信息
     *
     * @param userId
     * @param courseId
     * @return
     */
    @Override
    public LearningLesson queryByUserAndCourseId(Long userId, Long courseId) {
        return getOne(buildUserIdAndCourseIdWrapper(userId, courseId));
    }

    /**
     * 7、校验当前课程是否已经报名（Day2 - 作业5）
     *
     * @param courseId
     * @return
     */
    @Override
    public Long isLessonValid(Long courseId) {
        // 1.获取登录用户
        Long userId = UserContext.getUser();
        if (userId == null) {
            return null;
        }
        // 2.查询课程
        LearningLesson lesson = getOne(buildUserIdAndCourseIdWrapper(userId, courseId));
        if (lesson == null || LessonStatus.EXPIRED.equals(lesson.getStatus())) {
            return null;
        }
        return lesson.getId();
    }


    private LambdaQueryWrapper<LearningLesson> buildUserIdAndCourseIdWrapper(Long userId, Long courseId) {
        LambdaQueryWrapper<LearningLesson> queryWrapper = new QueryWrapper<LearningLesson>()
                .lambda()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId);
        return queryWrapper;
    }



}
